4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
16 namespace Microsoft
.JScript
{
19 using System
.Collections
;
20 using System
.Globalization
;
21 using System
.Reflection
;
22 using System
.Reflection
.Emit
;
24 public abstract class Binding
: AST
{
25 private IReflect
[] argIRs
;
26 protected MemberInfo defaultMember
;
27 private IReflect defaultMemberReturnIR
;
28 private bool isArrayElementAccess
;
29 private bool isArrayConstructor
;
30 protected bool isAssignmentToDefaultIndexedProperty
;
31 protected bool isFullyResolved
;
32 protected bool isNonVirtual
;
33 internal MemberInfo
[] members
;
34 internal MemberInfo member
;
35 protected String name
;
36 private bool giveErrors
;
38 static internal ConstantWrapper ReflectionMissingCW
= new ConstantWrapper(System
.Reflection
.Missing
.Value
, null);
39 static private ConstantWrapper JScriptMissingCW
= new ConstantWrapper(Missing
.Value
, null);
41 internal Binding(Context context
, String name
)
44 this.defaultMember
= null;
45 this.defaultMemberReturnIR
= null;
46 this.isArrayElementAccess
= false;
47 this.isArrayConstructor
= false;
48 this.isAssignmentToDefaultIndexedProperty
= false;
49 this.isFullyResolved
= true;
50 this.isNonVirtual
= false;
54 this.giveErrors
= true;
57 private bool Accessible(bool checkSetter
){
58 if (this.member
== null) return false;
59 switch(this.member
.MemberType
){
60 case MemberTypes
.Constructor
: return AccessibleConstructor();
61 case MemberTypes
.Event
: return false;
62 case MemberTypes
.Field
: return AccessibleField(checkSetter
);
63 case MemberTypes
.Method
: return AccessibleMethod();
64 case MemberTypes
.NestedType
:
65 if (!((Type
)this.member
).IsNestedPublic
){
67 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
73 case MemberTypes
.TypeInfo
:
74 if (!((Type
)this.member
).IsPublic
){
76 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
82 case MemberTypes
.Property
: return AccessibleProperty(checkSetter
);
87 private bool AccessibleConstructor(){
88 ConstructorInfo cons
= (ConstructorInfo
)this.member
;
89 if ((cons
is JSConstructor
&& ((JSConstructor
)member
).GetClassScope().owner
.isAbstract
) ||
90 (!(cons
is JSConstructor
) && cons
.DeclaringType
.IsAbstract
)){
91 this.context
.HandleError(JSError
.CannotInstantiateAbstractClass
);
94 if (cons
.IsPublic
) return true;
95 if (cons
is JSConstructor
){
96 if (((JSConstructor
)cons
).IsAccessibleFrom(Globals
.ScopeStack
.Peek())) return true;
99 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
103 private bool AccessibleField(bool checkWritable
){
104 FieldInfo field
= (FieldInfo
)this.member
;
105 if (checkWritable
&& (field
.IsInitOnly
|| field
.IsLiteral
)) return false;
106 if (!field
.IsPublic
){
107 JSWrappedField wfield
= field
as JSWrappedField
;
109 this.member
= field
= wfield
.wrappedField
;
110 JSClosureField cfield
= field
as JSClosureField
;
111 JSMemberField mfield
= (cfield
!= null ? cfield
.field
: field
) as JSMemberField
;
113 if ((!field
.IsFamily
&& !field
.IsFamilyOrAssembly
) || !Binding
.InsideClassThatExtends(Globals
.ScopeStack
.Peek(), field
.ReflectedType
)){
115 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
118 }else if (!mfield
.IsAccessibleFrom(Globals
.ScopeStack
.Peek())){
120 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
124 if (field
.IsLiteral
&& field
is JSVariableField
){
125 ClassScope csc
= ((JSVariableField
)field
).value as ClassScope
;
126 if (csc
!= null && !csc
.owner
.IsStatic
){
127 Lookup lookup
= this as Lookup
;
128 if (lookup
== null || !lookup
.InStaticCode() || lookup
.InFunctionNestedInsideInstanceMethod()) return true;
130 this.context
.HandleError(JSError
.InstanceNotAccessibleFromStatic
, this.isFullyResolved
);
134 if (field
.IsStatic
|| field
.IsLiteral
|| this.defaultMember
!= null || !(this is Lookup
) || !((Lookup
)this).InStaticCode()) return true;
135 if (field
is JSWrappedField
&& field
.DeclaringType
== Typeob
.LenientGlobalObject
) return true;
136 if (this.giveErrors
) {
137 if (!field
.IsStatic
&& this is Lookup
&& ((Lookup
)this).InStaticCode())
138 this.context
.HandleError(JSError
.InstanceNotAccessibleFromStatic
, this.isFullyResolved
);
140 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
145 private bool AccessibleMethod(){
146 MethodInfo meth
= (MethodInfo
)this.member
;
147 return this.AccessibleMethod(meth
);
150 private bool AccessibleMethod(MethodInfo meth
){
151 if (meth
== null) return false;
152 if (this.isNonVirtual
&& meth
.IsAbstract
){
153 this.context
.HandleError(JSError
.InvalidCall
);
157 JSWrappedMethod wmeth
= meth
as JSWrappedMethod
;
160 JSClosureMethod cmeth
= meth
as JSClosureMethod
;
161 JSFieldMethod fmeth
= (cmeth
!= null ? cmeth
.method
: meth
) as JSFieldMethod
;
163 if ((meth
.IsFamily
|| meth
.IsFamilyOrAssembly
) && Binding
.InsideClassThatExtends(Globals
.ScopeStack
.Peek(), meth
.ReflectedType
))
166 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
168 }else if (!fmeth
.IsAccessibleFrom(Globals
.ScopeStack
.Peek())){
170 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
174 if (meth
.IsStatic
|| this.defaultMember
!= null || !(this is Lookup
) || !((Lookup
)this).InStaticCode()) return true;
175 if (meth
is JSWrappedMethod
&& ((Lookup
)this).CanPlaceAppropriateObjectOnStack(((JSWrappedMethod
)meth
).obj
)) return true;
176 if (this.giveErrors
) {
177 if (!meth
.IsStatic
&& this is Lookup
&& ((Lookup
)this).InStaticCode())
178 this.context
.HandleError(JSError
.InstanceNotAccessibleFromStatic
, this.isFullyResolved
);
180 this.context
.HandleError(JSError
.NotAccessible
, this.isFullyResolved
);
185 private bool AccessibleProperty(bool checkSetter
){
186 PropertyInfo prop
= (PropertyInfo
)this.member
;
187 if (this.AccessibleMethod(checkSetter
? JSProperty
.GetSetMethod(prop
, true) : JSProperty
.GetGetMethod(prop
, true))) return true;
188 if (this.giveErrors
&& !checkSetter
) this.context
.HandleError(JSError
.WriteOnlyProperty
);
192 internal static bool AssignmentCompatible(IReflect lhir
, AST rhexpr
, IReflect rhir
, bool reportError
){
193 if (rhexpr
is ConstantWrapper
){
194 Object rhval
= rhexpr
.Evaluate();
195 if (rhval
is ClassScope
){
196 if (lhir
== Typeob
.Type
|| lhir
== Typeob
.Object
|| lhir
== Typeob
.String
) return true;
198 if (reportError
) rhexpr
.context
.HandleError(JSError
.TypeMismatch
);
202 ClassScope csc
= lhir
as ClassScope
;
204 EnumDeclaration ed
= csc
.owner
as EnumDeclaration
;
206 ConstantWrapper cw
= rhexpr
as ConstantWrapper
;
207 if (cw
!= null && cw
.value is String
){
208 FieldInfo field
= csc
.GetField((String
)cw
.value, BindingFlags
.Public
|BindingFlags
.Static
);
209 if (field
== null) return false;
210 ed
.PartiallyEvaluate();
211 cw
.value = new DeclaredEnumValue(((JSMemberField
)field
).value, field
.Name
, csc
);
213 if (rhir
== Typeob
.String
) return true;
214 lhir
= ed
.baseType
.ToType();
216 } else if (lhir
is Type
) {
217 Type type
= lhir
as Type
;
219 ConstantWrapper cw
= rhexpr
as ConstantWrapper
;
220 if (cw
!= null && cw
.value is String
){
221 FieldInfo field
= type
.GetField((String
)cw
.value, BindingFlags
.Public
|BindingFlags
.Static
);
222 if (field
== null) return false;
223 cw
.value = MetadataEnumValue
.GetEnumValue(field
.FieldType
, field
.GetRawConstantValue());
225 if (rhir
== Typeob
.String
) return true;
226 lhir
= Enum
.GetUnderlyingType(type
);
232 Convert
.CoerceT(rhval
, (Type
)lhir
);
235 if (lhir
== Typeob
.Single
&& rhval
is Double
){
236 if (((ConstantWrapper
)rhexpr
).isNumericLiteral
) return true;
237 Double d
= (Double
)rhval
;
238 Single s
= (Single
)d
;
239 if (d
.ToString(CultureInfo
.InvariantCulture
).Equals(s
.ToString(CultureInfo
.InvariantCulture
))){
240 ((ConstantWrapper
)rhexpr
).value = s
;
244 if (lhir
== Typeob
.Decimal
){
245 ConstantWrapper cw
= rhexpr
as ConstantWrapper
;
246 if (cw
!= null && cw
.isNumericLiteral
){
248 Convert
.CoerceT(cw
.context
.GetCode(), Typeob
.Decimal
);
254 rhexpr
.context
.HandleError(JSError
.TypeMismatch
);
258 }else if (rhexpr
is ArrayLiteral
)
259 return ((ArrayLiteral
)rhexpr
).AssignmentCompatible(lhir
, reportError
);
260 if (rhir
== Typeob
.Object
) return true; //Too little is known about the expression to complain at compile time
261 if (rhir
== Typeob
.Double
&& Convert
.IsPrimitiveNumericType(lhir
)) return true; //Arithmetic expressions infer to Double, but might have the right result.
262 if (lhir
is Type
&& Typeob
.Delegate
.IsAssignableFrom((Type
)lhir
) && rhir
== Typeob
.ScriptFunction
&&
263 rhexpr
is Binding
&& ((Binding
)rhexpr
).IsCompatibleWithDelegate((Type
)lhir
))
265 if (Convert
.IsPromotableTo(rhir
, lhir
))
266 return true; //rhexpr delivers a value that can be converted to something expected by the assignment target
267 if (Convert
.IsJScriptArray(rhir
) && Binding
.ArrayAssignmentCompatible(rhexpr
, lhir
))
269 if (lhir
== Typeob
.String
)
270 return true; // Everything is assignment-compatible to string.
271 if (rhir
== Typeob
.String
&& (lhir
== Typeob
.Boolean
|| Convert
.IsPrimitiveNumericType(lhir
))){
272 if (reportError
) rhexpr
.context
.HandleError(JSError
.PossibleBadConversionFromString
);
275 if ((lhir
== Typeob
.Char
&& rhir
== Typeob
.String
) || Convert
.IsPromotableTo(lhir
, rhir
) ||
276 (Convert
.IsPrimitiveNumericType(lhir
) && Convert
.IsPrimitiveNumericType(rhir
))){
277 if (reportError
) rhexpr
.context
.HandleError(JSError
.PossibleBadConversion
);
282 rhexpr
.context
.HandleError(JSError
.TypeMismatch
);
286 private static bool ArrayAssignmentCompatible(AST ast
, IReflect lhir
){
287 // If we've made it here then we already know that lhir is not Object or String
288 // and that a JScript array is not promotable to lhir. There are cases where
289 // a JScript array is not promotable but is assignable with a warning. A
290 // JScript array is assignable to a System.Array or to a rank-one typed array.
291 if (!Convert
.IsArray(lhir
))
293 else if (lhir
== Typeob
.Array
){
294 ast
.context
.HandleError(JSError
.ArrayMayBeCopied
);
296 }else if (Convert
.GetArrayRank(lhir
) == 1){
297 ast
.context
.HandleError(JSError
.ArrayMayBeCopied
);
303 internal void CheckIfDeletable(){
304 if (this.member
!= null || this.defaultMember
!= null)
305 this.context
.HandleError(JSError
.NotDeletable
);
307 this.defaultMember
= null;
310 internal void CheckIfUseless(){
311 // This is called for expression statements. There are no cases where an
312 // expression which just retrieves a property should not give a warning.
313 // We don't bother giving a warning if members is empty because more than
314 // likely an warning or error was already issued.
315 if (this.members
== null || this.members
.Length
== 0)
317 this.context
.HandleError(JSError
.UselessExpression
);
320 internal static bool CheckParameters(ParameterInfo
[] pars
, IReflect
[] argIRs
, ASTList argAST
, Context ctx
){
321 return Binding
.CheckParameters(pars
, argIRs
, argAST
, ctx
, 0, false, true);
324 internal static bool CheckParameters(ParameterInfo
[] pars
, IReflect
[] argIRs
, ASTList argAST
, Context ctx
, int offset
, bool defaultIsUndefined
, bool reportError
){
325 int n
= argIRs
.Length
;
327 bool tooManyParams
= false;
328 if (n
> m
-offset
) {n = m-offset; tooManyParams = true;}
329 for (int i
= 0; i
< n
; i
++){
330 IReflect formalIR
= (pars
[i
+offset
] is ParameterDeclaration
) ? ((ParameterDeclaration
)pars
[i
+offset
]).ParameterIReflect
: pars
[i
+offset
].ParameterType
;
331 IReflect actualIR
= argIRs
[i
];
332 if (i
== n
-1 && ((formalIR
is Type
&& Typeob
.Array
.IsAssignableFrom((Type
)formalIR
)) || formalIR
is TypedArray
) &&
333 CustomAttribute
.IsDefined(pars
[i
+offset
], typeof(ParamArrayAttribute
), false)){
334 tooManyParams
= false;
335 int k
= argIRs
.Length
;
337 if (Binding
.AssignmentCompatible(formalIR
, argAST
[i
], argIRs
[i
], false))
340 IReflect elemIR
= formalIR
is Type
? ((Type
)formalIR
).GetElementType() : ((TypedArray
)formalIR
).elementType
;
341 for (int j
= i
; j
< k
; j
++)
342 if (!Binding
.AssignmentCompatible(elemIR
, argAST
[j
], argIRs
[j
], reportError
)) return false;
345 if (!Binding
.AssignmentCompatible(formalIR
, argAST
[i
], actualIR
, reportError
)) return false;
347 if (tooManyParams
&& reportError
)
348 ctx
.HandleError(JSError
.TooManyParameters
);
349 if (offset
== 0 && n
< m
&& !defaultIsUndefined
) //Fewer actual parameters than formal parameters
350 for (int j
= n
; j
< m
; j
++)
351 if (TypeReferences
.GetDefaultParameterValue(pars
[j
]) == System
.Convert
.DBNull
){ //No default value specified
352 //Ensure that custom attribute has been resolved before checking
353 ParameterDeclaration pardecl
= pars
[j
] as ParameterDeclaration
;
355 pardecl
.PartiallyEvaluate();
356 if (j
< m
-1 || !CustomAttribute
.IsDefined(pars
[j
], typeof(ParamArrayAttribute
), false)){
358 ctx
.HandleError(JSError
.TooFewParameters
);
359 IReflect formalIR
= (pars
[j
+offset
] is ParameterDeclaration
) ? ((ParameterDeclaration
)pars
[j
+offset
]).ParameterIReflect
: pars
[j
+offset
].ParameterType
;
360 Type formalType
= formalIR
as Type
;
361 if (formalType
!= null && formalType
.IsValueType
&& !formalType
.IsPrimitive
&& !formalType
.IsEnum
)
362 return false; //Can't generate valid code for this since there is no general mapping from undefined to value types
368 internal override bool Delete(){
369 return this.EvaluateAsLateBinding().Delete();
372 internal override Object
Evaluate(){
373 Object ob
= this.GetObject();
374 MemberInfo member
= this.member
;
376 switch(member
.MemberType
){
377 case MemberTypes
.Field
: return ((FieldInfo
)member
).GetValue(ob
);
378 case MemberTypes
.Property
:
379 MemberInfo
[] members
= new MemberInfo
[]{JSProperty.GetGetMethod((PropertyInfo)member, false)}
;
380 return LateBinding
.CallOneOfTheMembers(members
, new Object
[0], false, ob
, null, null, null, this.Engine
);
381 case MemberTypes
.Event
: return null;
382 case MemberTypes
.NestedType
: return member
;
384 if (this.members
!= null && this.members
.Length
> 0){
385 //Special case check for methods on builtin objects
386 if (this.members
.Length
== 1 && this.members
[0].MemberType
== MemberTypes
.Method
){
387 MethodInfo meth
= (MethodInfo
)members
[0];
388 Type dt
= meth
is JSMethod
? null : meth
.DeclaringType
;
390 if (dt
== Typeob
.GlobalObject
||
391 (dt
!= null && dt
!= Typeob
.StringObject
&& dt
!= Typeob
.NumberObject
&& dt
!= Typeob
.BooleanObject
&& dt
.IsSubclassOf(Typeob
.JSObject
))){
392 //This only happens in fast mode. We could add InitOnly fields to the fast predefined objects and initialize them
393 //with instances of BuiltinFunction objects, in which case we would never get here, but we would like to avoid
394 //the start up cost of allocating these objects, particularly if they end up never being used (the expected common case).
395 return Globals
.BuiltinFunctionFor(ob
, TypeReferences
.ToExecutionContext(meth
));
396 //Note that meth is not wrapped because it is static
400 return new FunctionWrapper(this.name
, ob
, this.members
);
402 return this.EvaluateAsLateBinding().GetValue();
405 //Returns a list of member infos that are sorted by declaring type. Superclass members always follow derived class members.
406 private MemberInfoList
GetAllKnownInstanceBindingsForThisName(){
407 IReflect
[] classes
= this.GetAllEligibleClasses();
408 MemberInfoList result
= new MemberInfoList();
409 foreach (IReflect c
in classes
){
410 if (c
is ClassScope
){
411 if (((ClassScope
)c
).ParentIsInSamePackage())
412 result
.AddRange(c
.GetMember(name
, BindingFlags
.Public
|BindingFlags
.NonPublic
|BindingFlags
.Instance
|BindingFlags
.DeclaredOnly
));
414 result
.AddRange(c
.GetMember(name
, BindingFlags
.Public
|BindingFlags
.NonPublic
|BindingFlags
.Instance
));
416 result
.AddRange(c
.GetMember(name
, BindingFlags
.Public
|BindingFlags
.Instance
));
421 //Returns a list of the classes visible from the current scope.
422 //Currently, classes are returned only if they are ancestors of the current class, or reside in the same package.
423 private IReflect
[] GetAllEligibleClasses(){
424 ArrayList classes
= new ArrayList(16);
425 ClassScope currentClass
= null;
426 PackageScope currentPackage
= null;
427 ScriptObject scope
= Globals
.ScopeStack
.Peek();
428 while (scope
is WithObject
|| scope
is BlockScope
)
429 scope
= scope
.GetParent();
430 if (scope
is FunctionScope
)
431 scope
= ((FunctionScope
)scope
).owner
.enclosing_scope
;
432 if (scope
is ClassScope
){
433 currentClass
= (ClassScope
)scope
;
434 currentPackage
= currentClass
.package
;
436 if (currentClass
!= null)
437 currentClass
.AddClassesFromInheritanceChain(this.name
, classes
);
438 if (currentPackage
!= null)
439 currentPackage
.AddClassesExcluding(currentClass
, this.name
, classes
);
441 ((IActivationObject
)scope
).GetGlobalScope().AddClassesExcluding(currentClass
, this.name
, classes
);
442 IReflect
[] result
= new IReflect
[classes
.Count
]; classes
.CopyTo(result
);
446 protected abstract Object
GetObject();
448 protected abstract void HandleNoSuchMemberError();
450 internal override IReflect
InferType(JSField inference_target
){
451 Debug
.Assert(this.members
!= null); //Have to call a PartiallyEvaluate routine before calling InferType
452 if (this.isArrayElementAccess
){
453 IReflect ir
= this.defaultMemberReturnIR
;
454 return ir
is TypedArray
? ((TypedArray
)ir
).elementType
: ((Type
)ir
).GetElementType();
456 if (this.isAssignmentToDefaultIndexedProperty
){
457 if (this.member
is PropertyInfo
) //Could be null if no binding was found
458 return ((PropertyInfo
)this.member
).PropertyType
;
459 return Typeob
.Object
;
461 MemberInfo member
= this.member
;
462 if (member
is FieldInfo
){
463 JSWrappedField wf
= member
as JSWrappedField
;
464 if (wf
!= null) member
= wf
.wrappedField
;
465 if (member
is JSVariableField
)
466 return ((JSVariableField
)member
).GetInferredType(inference_target
);
468 return ((FieldInfo
)member
).FieldType
;
470 if (member
is PropertyInfo
) {
471 JSWrappedProperty wp
= member
as JSWrappedProperty
;
472 if (wp
!= null) member
= wp
.property
;
473 if (member
is JSProperty
)
474 return ((JSProperty
)member
).PropertyIR();
476 PropertyInfo prop
= (PropertyInfo
)member
;
477 if (prop
.DeclaringType
== Typeob
.GlobalObject
)
478 return (IReflect
)prop
.GetValue(this.Globals
.globalObject
, null);
480 return prop
.PropertyType
;
486 if (member
is EventInfo
)
487 return Typeob
.EventInfo
;
488 if (this.members
.Length
> 0 && this.Engine
.doFast
)
489 return Typeob
.ScriptFunction
;
490 return Typeob
.Object
;
493 internal virtual IReflect
InferTypeOfCall(JSField inference_target
, bool isConstructor
){
494 Debug
.Assert(this.members
!= null); //Have to call a PartiallyEvaluate routine before calling InferTypeOfCall
495 if (!this.isFullyResolved
) return Typeob
.Object
;
496 if (this.isArrayConstructor
)
497 return this.defaultMemberReturnIR
;
498 if (this.isArrayElementAccess
){
499 IReflect ir
= this.defaultMemberReturnIR
;
500 return ir
is TypedArray
? ((TypedArray
)ir
).elementType
: ((Type
)ir
).GetElementType();
502 MemberInfo member
= this.member
;
503 if (member
is JSFieldMethod
) return isConstructor
? Typeob
.Object
: ((JSFieldMethod
)member
).ReturnIR();
504 if (member
is MethodInfo
) return ((MethodInfo
)member
).ReturnType
;
505 if (member
is JSConstructor
) return ((JSConstructor
)member
).GetClassScope();
506 if (member
is ConstructorInfo
) return ((ConstructorInfo
)member
).DeclaringType
;
507 if (member
is Type
) return (Type
)member
;
508 if (member
is FieldInfo
&& ((FieldInfo
)member
).IsLiteral
){
509 Object val
= member
is JSVariableField
? ((JSVariableField
)member
).value : TypeReferences
.GetConstantValue((FieldInfo
)member
);
510 if (val
is ClassScope
|| val
is TypedArray
) return (IReflect
)val
;
512 return Typeob
.Object
;
515 private static bool InsideClassThatExtends(ScriptObject scope
, Type type
){
516 while (scope
is WithObject
|| scope
is BlockScope
)
517 scope
= scope
.GetParent();
518 if (scope
is ClassScope
)
519 return type
.IsAssignableFrom(((ClassScope
)scope
).GetBakedSuperType());
520 if (scope
is FunctionScope
)
521 return Binding
.InsideClassThatExtends(((FunctionScope
)scope
).owner
.enclosing_scope
, type
);
522 //Eval does not see non public members, so don't worry about StackFrame
526 internal void InvalidateBinding(){
527 this.isAssignmentToDefaultIndexedProperty
= false;
528 this.isArrayConstructor
= false;
529 this.isArrayElementAccess
= false;
530 this.defaultMember
= null;
532 this.members
= new MemberInfo
[0];
535 internal bool IsCompatibleWithDelegate(Type delegateType
){
536 Debug
.Assert(this.members
!= null && this.members
.Length
> 0);
537 MethodInfo invoke
= delegateType
.GetMethod("Invoke");
538 ParameterInfo
[] dparams
= invoke
.GetParameters();
539 Type drtype
= invoke
.ReturnType
;
540 foreach (MemberInfo mem
in this.members
){
541 if (mem
is MethodInfo
){
542 MethodInfo meth
= (MethodInfo
)mem
;
543 Type returnType
= null;
544 if (meth
is JSFieldMethod
){
545 IReflect returnIR
= ((JSFieldMethod
)meth
).ReturnIR();
546 if (returnIR
is ClassScope
)
547 returnType
= ((ClassScope
)returnIR
).GetBakedSuperType(); //JScript cannot define delegates, so baked is OK.
548 else if (returnIR
is Type
)
549 returnType
= (Type
)returnIR
;
551 returnType
= Convert
.ToType(returnIR
);
552 if (((JSFieldMethod
)meth
).func
.isExpandoMethod
) return false;
554 returnType
= meth
.ReturnType
;
555 if (returnType
== drtype
&& Class
.ParametersMatch(dparams
, meth
.GetParameters())){
557 this.isFullyResolved
= true;
565 public static bool IsMissing(Object
value){
566 return value is Missing
;
569 private MethodInfo
LookForParameterlessPropertyGetter(){
570 // We only get here as a result of an AmbiguousMatchException. If all the matches are parameterless
571 // property getters, we try selecting a match without providing arguments.
572 for (int i
=0, n
=this.members
.Length
; i
<n
; i
++){
573 PropertyInfo prop
= this.members
[i
] as PropertyInfo
;
575 MethodInfo meth
= prop
.GetGetMethod(true);
576 if (meth
== null) continue;
577 ParameterInfo
[] parameters
= meth
.GetParameters();
578 if (parameters
== null || parameters
.Length
== 0) continue;
583 MethodInfo meth
= JSBinder
.SelectMethod(this.members
, new IReflect
[0]); //Returns property getters as well
584 if (meth
!= null && meth
.IsSpecialName
){ //Property getter.
587 }catch(AmbiguousMatchException
){
592 internal override bool OkToUseAsType(){
593 MemberInfo member
= this.member
;
594 if (member
is Type
) return this.isFullyResolved
= true;
595 if (member
is FieldInfo
){
596 FieldInfo field
= (FieldInfo
)member
;
597 if (field
.IsLiteral
){
598 if (field
is JSMemberField
&& ((JSMemberField
)field
).value is ClassScope
&& !field
.IsStatic
)
600 return this.isFullyResolved
= true;
602 if (!(member
is JSField
) && field
.IsStatic
&& field
.GetValue(null) is Type
) return this.isFullyResolved
= true;
607 private int PlaceValuesForHiddenParametersOnStack(ILGenerator il
, MethodInfo meth
, ParameterInfo
[] pars
){
609 if (meth
is JSFieldMethod
){
610 FunctionObject func
= ((JSFieldMethod
)meth
).func
;
611 if (func
!= null && func
.isMethod
) return 0;
613 ((Lookup
)this).TranslateToILDefaultThisObject(il
);
615 this.TranslateToILObject(il
, Typeob
.Object
, false);
616 this.EmitILToLoadEngine(il
);
619 Object
[] attrs
= CustomAttribute
.GetCustomAttributes(meth
, typeof(JSFunctionAttribute
), false);
620 if (attrs
== null || attrs
.Length
== 0) return 0;
621 JSFunctionAttributeEnum attr
= ((JSFunctionAttribute
)attrs
[0]).attributeValue
;
622 if ((attr
& JSFunctionAttributeEnum
.HasThisObject
) != 0){
624 Type pt
= pars
[0].ParameterType
;
625 if (this is Lookup
&& pt
== Typeob
.Object
)
626 ((Lookup
)this).TranslateToILDefaultThisObject(il
);
628 if (Typeob
.ArrayObject
.IsAssignableFrom(member
.DeclaringType
))
629 this.TranslateToILObject(il
, Typeob
.ArrayObject
, false);
631 this.TranslateToILObject(il
, pt
, false);
634 if ((attr
& JSFunctionAttributeEnum
.HasEngine
) != 0){
636 this.EmitILToLoadEngine(il
);
641 private bool ParameterlessPropertyValueIsCallable(MethodInfo meth
, ASTList args
, IReflect
[] argIRs
, bool constructor
, bool brackets
){
642 ParameterInfo
[] pars
= meth
.GetParameters();
643 if (pars
== null || pars
.Length
== 0){
644 if ((meth
is JSWrappedMethod
&& ((JSWrappedMethod
)meth
).GetWrappedObject() is GlobalObject
) ||
646 (!(meth
is JSMethod
) && Typeob
.ScriptFunction
.IsAssignableFrom(meth
.ReturnType
))){
647 this.member
= this.ResolveOtherKindOfCall(args
, argIRs
, constructor
, brackets
);
650 IReflect mrt
= meth
is JSFieldMethod
? ((JSFieldMethod
)meth
).ReturnIR() : meth
.ReturnType
;
651 if (mrt
!= Typeob
.Object
&& mrt
!= Typeob
.ScriptFunction
)
652 this.context
.HandleError(JSError
.InvalidCall
);
654 this.member
= this.ResolveOtherKindOfCall(args
, argIRs
, constructor
, brackets
);
661 internal static void PlaceArgumentsOnStack(ILGenerator il
, ParameterInfo
[] pars
, ASTList args
, int offset
, int rhoffset
, AST missing
){
664 int m
= pars
.Length
-rhoffset
;
665 bool varargs
= m
> 0 && CustomAttribute
.IsDefined(pars
[m
-1], typeof(ParamArrayAttribute
), false) &&
666 !(k
== m
&& Convert
.IsArrayType(args
[k
-1].InferType(null)));
667 Type varargElemType
= varargs
? pars
[--m
].ParameterType
.GetElementType() : null;
669 for (int i
= offset
; i
< n
; i
++){
670 Type ptype
= pars
[i
].ParameterType
;
671 AST arg
= args
[i
-offset
];
672 if (arg
is ConstantWrapper
&& ((ConstantWrapper
)arg
).value == System
.Reflection
.Missing
.Value
){
673 Object defVal
= TypeReferences
.GetDefaultParameterValue(pars
[i
]);
674 ((ConstantWrapper
)arg
).value = defVal
!= System
.Convert
.DBNull
? defVal
: null;
677 arg
.TranslateToILReference(il
, ptype
.GetElementType());
679 arg
.TranslateToIL(il
, ptype
);
682 for (int i
= n
; i
< m
; i
++){
683 Type ptype
= pars
[i
].ParameterType
;
684 if (TypeReferences
.GetDefaultParameterValue(pars
[i
]) == System
.Convert
.DBNull
) //No default value was specified
686 missing
.TranslateToILReference(il
, ptype
.GetElementType());
688 missing
.TranslateToIL(il
, ptype
);
691 (new ConstantWrapper(TypeReferences
.GetDefaultParameterValue(pars
[i
]), null)).TranslateToILReference(il
, ptype
.GetElementType());
693 (new ConstantWrapper(TypeReferences
.GetDefaultParameterValue(pars
[i
]), null)).TranslateToIL(il
, ptype
);
697 n
-= offset
; //The number of arguments in argList that are already on the stack
698 m
= k
>n
? k
-n
: 0; //The number of arguments in argList that are to be placed in the vararg array
699 ConstantWrapper
.TranslateToILInt(il
, m
);
700 il
.Emit(OpCodes
.Newarr
, varargElemType
);
701 bool doLdelema
= varargElemType
.IsValueType
&& !varargElemType
.IsPrimitive
;
702 for (int i
= 0; i
< m
; i
++){
703 il
.Emit(OpCodes
.Dup
);
704 ConstantWrapper
.TranslateToILInt(il
, i
);
706 il
.Emit(OpCodes
.Ldelema
, varargElemType
);
707 args
[i
+n
].TranslateToIL(il
, varargElemType
);
708 Binding
.TranslateToStelem(il
, varargElemType
);
713 internal bool RefersToMemoryLocation(){
714 if (this.isFullyResolved
){
715 if (this.isArrayElementAccess
) return true;
716 return this.member
is FieldInfo
;
721 internal override void ResolveCall(ASTList args
, IReflect
[] argIRs
, bool constructor
, bool brackets
){
722 this.argIRs
= argIRs
;
723 if (this.members
== null || this.members
.Length
== 0){
724 if (constructor
&& this.isFullyResolved
&& this.Engine
.doFast
)
725 if (this.member
!= null && (this.member
is Type
|| (this.member
is FieldInfo
&& ((FieldInfo
)this.member
).IsLiteral
)))
726 this.context
.HandleError(JSError
.NoConstructor
);
728 this.HandleNoSuchMemberError();
730 this.HandleNoSuchMemberError();
731 return; //Have to do a runtime lookup
733 MemberInfo member
= null;
734 if (!(this is CallableExpression
) && !(constructor
&& brackets
))
737 this.member
= member
= JSBinder
.SelectConstructor(this.members
, argIRs
);
740 this.member
= member
= meth
= JSBinder
.SelectMethod(this.members
, argIRs
); //Returns property getters as well
741 if (meth
!= null && meth
.IsSpecialName
){ //Property getter.
742 if (this.name
== meth
.Name
){
743 if (this.name
.StartsWith("get_", StringComparison
.Ordinal
) || this.name
.StartsWith("set_", StringComparison
.Ordinal
)){
744 this.context
.HandleError(JSError
.NotMeantToBeCalledDirectly
);
748 }else if (this.ParameterlessPropertyValueIsCallable(meth
, args
, argIRs
, constructor
, brackets
))
749 return; // this.member was set by ParameterlessPropertyValueIsCallable
752 }catch(AmbiguousMatchException
){
754 this.context
.HandleError(JSError
.AmbiguousConstructorCall
, this.isFullyResolved
);
756 MethodInfo meth
= this.LookForParameterlessPropertyGetter();
757 if (meth
!= null && this.ParameterlessPropertyValueIsCallable(meth
, args
, argIRs
, constructor
, brackets
))
758 return; // this.member was set by ParameterlessPropertyValueIsCallable
759 this.context
.HandleError(JSError
.AmbiguousMatch
, this.isFullyResolved
);
763 }catch(JScriptException e
){
764 this.context
.HandleError((Microsoft
.JScript
.JSError
)(e
.ErrorNumber
& 0xffff), e
.Message
, true);
768 member
= this.ResolveOtherKindOfCall(args
, argIRs
, constructor
, brackets
);
769 if (member
== null) return; //Already complained about it, if applicable. Do runtime lookup.
770 if (!this.Accessible(false)){
775 if (member
is MethodBase
){
776 if (CustomAttribute
.IsDefined(member
, typeof(JSFunctionAttribute
), false) && !(this.defaultMember
is PropertyInfo
)){
778 Object
[] attrs
= CustomAttribute
.GetCustomAttributes(member
, typeof(JSFunctionAttribute
), false);
779 JSFunctionAttributeEnum attr
= ((JSFunctionAttribute
)attrs
[0]).attributeValue
;
780 if ((constructor
&& !(member
is ConstructorInfo
)) || (attr
& JSFunctionAttributeEnum
.HasArguments
) != 0){
781 //Can only happen when doing an Eval from slow mode code
782 //Cannot call such methods directly, so bind to the associated field instead
783 this.member
= LateBinding
.SelectMember(this.members
);
784 this.defaultMember
= null;
787 if ((attr
& JSFunctionAttributeEnum
.HasThisObject
) != 0)
789 if ((attr
& JSFunctionAttributeEnum
.HasEngine
) != 0)
791 if (!Binding
.CheckParameters(((MethodBase
)member
).GetParameters(), argIRs
, args
, this.context
, hidden
, true, this.isFullyResolved
)){
795 }else if (constructor
&& member
is JSFieldMethod
){
796 //Do a late bound call so that the function as constructor semantics work out
797 this.member
= LateBinding
.SelectMember(this.members
);
799 }else if (constructor
&& member
is ConstructorInfo
&& !(member
is JSConstructor
) && Typeob
.Delegate
.IsAssignableFrom(member
.DeclaringType
)){
800 this.context
.HandleError(JSError
.DelegatesShouldNotBeExplicitlyConstructed
);
804 if (!Binding
.CheckParameters(((MethodBase
)member
).GetParameters(), argIRs
, args
, this.context
, 0, false, this.isFullyResolved
)){
812 internal override Object
ResolveCustomAttribute(ASTList args
, IReflect
[] argIRs
, AST target
){
814 this.ResolveCall(args
, argIRs
, true, false);
815 }catch(AmbiguousMatchException
){
816 this.context
.HandleError(JSError
.AmbiguousConstructorCall
);
819 JSConstructor jscons
= this.member
as JSConstructor
;
821 ClassScope csc
= jscons
.GetClassScope();
822 if (csc
.owner
.IsCustomAttribute()) return csc
;
824 ConstructorInfo cons
= this.member
as ConstructorInfo
;
826 Type attrType
= cons
.DeclaringType
;
827 if (Typeob
.Attribute
.IsAssignableFrom(attrType
)){
828 Object
[] usageAttrs
= CustomAttribute
.GetCustomAttributes(attrType
, typeof(AttributeUsageAttribute
), false);
829 if (usageAttrs
.Length
> 0) return attrType
;
833 this.context
.HandleError(JSError
.InvalidCustomAttributeClassOrCtor
);
837 internal void ResolveLHValue(){
838 MemberInfo member
= this.member
= LateBinding
.SelectMember(this.members
);
839 if ((member
!= null && !this.Accessible(true)) || (this.member
== null && this.members
.Length
> 0)){
840 this.context
.HandleError(JSError
.AssignmentToReadOnly
, this.isFullyResolved
);
841 this.member
= null; //Recover by going late bound. The runtime routine will fail silently
842 this.members
= new MemberInfo
[0];
845 if (member
is JSPrototypeField
){ //Go late bound
847 this.members
= new MemberInfo
[0];
850 this.WarnIfNotFullyResolved();
851 this.WarnIfObsolete();
855 private MemberInfo
ResolveOtherKindOfCall(ASTList argList
, IReflect
[] argIRs
, bool constructor
, bool brackets
){
856 //There is no method or constructor corresponding to this binding. But there is something else.
857 MemberInfo member
= this.member
= LateBinding
.SelectMember(this.members
); //Choose something
859 //If the chosen member is a read-only property on the global object of type Type, replace it with the type.
860 if (member
is PropertyInfo
&& !(member
is JSProperty
) && member
.DeclaringType
== Typeob
.GlobalObject
){
861 PropertyInfo prop
= (PropertyInfo
)member
;
862 Type ptype
= prop
.PropertyType
;
863 if (ptype
== Typeob
.Type
)
864 member
= (Type
)prop
.GetValue(null, null);
865 else if (constructor
&& brackets
){ //Map properties returning fast mode constructor functions to types
866 MethodInfo meth
= ptype
.GetMethod("CreateInstance", BindingFlags
.Public
|BindingFlags
.Instance
|BindingFlags
.DeclaredOnly
);
868 Type rtype
= meth
.ReturnType
;
869 if (rtype
== Typeob
.BooleanObject
)
870 member
= Typeob
.Boolean
;
871 else if (rtype
== Typeob
.StringObject
)
872 member
= Typeob
.String
;
879 //Check for casts to type expressions, i.e. int[](x)
880 CallableExpression ce
= this as CallableExpression
;
882 ConstantWrapper cw
= ce
.expression
as ConstantWrapper
;
883 if (cw
!= null && cw
.InferType(null) is Type
)
884 member
= new JSGlobalField(null, null, cw
.value, FieldAttributes
.Literal
|FieldAttributes
.Public
);
887 //If the chosen member is a literal field containing a class/function or a nested type, we replace members and try again.
891 this.isArrayConstructor
= true;
892 this.defaultMember
= member
;
893 this.defaultMemberReturnIR
= new TypedArray((Type
)member
, argIRs
.Length
);
894 for (int i
= 0, n
= argIRs
.Length
; i
< n
; i
++){
895 if (argIRs
[i
] != Typeob
.Object
&& !Convert
.IsPrimitiveNumericType(argIRs
[i
])){
896 argList
[i
].context
.HandleError(JSError
.TypeMismatch
, this.isFullyResolved
);
900 return this.member
= member
;
902 ConstructorInfo
[] constructors
= ((Type
)member
).GetConstructors(BindingFlags
.Instance
|BindingFlags
.Public
);
903 if (constructors
== null || constructors
.Length
== 0){
904 this.context
.HandleError(JSError
.NoConstructor
);
908 this.members
= constructors
;
909 this.ResolveCall(argList
, argIRs
, true, brackets
);
913 if (!brackets
&& argIRs
.Length
== 1){
914 //Dealing with a type cast
917 this.context
.HandleError(JSError
.InvalidCall
);
918 return this.member
= null;
921 if (member
is JSPrototypeField
)
922 //Have to go late-bound
923 return this.member
= null;
924 if (member
is FieldInfo
&& ((FieldInfo
)member
).IsLiteral
){
925 if (!this.AccessibleField(false)) return this.member
= null;
926 Object val
= member
is JSVariableField
? ((JSVariableField
)member
).value : TypeReferences
.GetConstantValue((FieldInfo
)member
);
927 if ((val
is ClassScope
|| val
is Type
)){
930 this.isArrayConstructor
= true;
931 this.defaultMember
= member
;
932 this.defaultMemberReturnIR
= new TypedArray((val
is ClassScope
? (IReflect
)val
: (IReflect
)val
), argIRs
.Length
);
933 for (int i
= 0, n
= argIRs
.Length
; i
< n
; i
++){
934 if (argIRs
[i
] != Typeob
.Object
&& !Convert
.IsPrimitiveNumericType(argIRs
[i
])){
935 argList
[i
].context
.HandleError(JSError
.TypeMismatch
, this.isFullyResolved
);
939 return this.member
= member
;
941 if (val
is ClassScope
&& !((ClassScope
)val
).owner
.isStatic
){
942 ConstantWrapper cw
= null;
943 if (this is Member
&& (cw
= ((Member
)this).rootObject
as ConstantWrapper
) != null && !(cw
.Evaluate() is Namespace
)){
944 ((Member
)this).rootObject
.context
.HandleError(JSError
.NeedInstance
);
948 this.members
= val
is ClassScope
? ((ClassScope
)val
).constructors
: ((Type
)val
).GetConstructors(BindingFlags
.Instance
|BindingFlags
.Public
);
949 if (this.members
== null || this.members
.Length
== 0){
950 this.context
.HandleError(JSError
.NoConstructor
);
954 this.ResolveCall(argList
, argIRs
, true, brackets
);
958 if (!brackets
&& argIRs
.Length
== 1){
959 Type ty
= val
as Type
;
960 return this.member
= (ty
!= null ? ty
: member
);
962 this.context
.HandleError(JSError
.InvalidCall
);
963 return this.member
= null;
966 if (val
is TypedArray
){
967 if (!constructor
){ //Casting a value to an array type
968 if (argIRs
.Length
!= 1 || brackets
) goto ReportError
;
969 return this.member
= member
;
971 if (!brackets
) goto ReportError
; //new T(...) where T is an array type.
972 if (argIRs
.Length
== 0) goto ReportError
; //new T[] where T is an array type.
973 this.isArrayConstructor
= true;
974 this.defaultMember
= member
;
975 this.defaultMemberReturnIR
= new TypedArray((IReflect
)val
, argIRs
.Length
);
976 for (int i
= 0, n
= argIRs
.Length
; i
< n
; i
++){
977 if (argIRs
[i
] != Typeob
.Object
&& !Convert
.IsPrimitiveNumericType(argIRs
[i
])){
978 argList
[i
].context
.HandleError(JSError
.TypeMismatch
, this.isFullyResolved
);
982 return this.member
= member
;
984 if (val
is FunctionObject
){
985 FunctionObject func
= (FunctionObject
)val
;
986 if (!func
.isExpandoMethod
&& !func
.Must_save_stack_locals
&& (func
.own_scope
.ProvidesOuterScopeLocals
== null || func
.own_scope
.ProvidesOuterScopeLocals
.count
== 0))
987 return this.member
= ((JSVariableField
)this.member
).GetAsMethod(func
.own_scope
);
988 return this.member
; //Have to call via the field so that the stack frame is set up correctly
992 //Check the type of this binding for more information
993 IReflect ir
= this.InferType(null);
995 if (!brackets
&& ((t
!= null && Typeob
.ScriptFunction
.IsAssignableFrom(t
)) || ir
is ScriptFunction
)){
996 this.defaultMember
= member
;
998 this.defaultMemberReturnIR
= Globals
.TypeRefs
.ToReferenceContext(ir
.GetType()); //The appropriate subtype of ScriptFunction
999 this.member
= this.defaultMemberReturnIR
.GetMethod(constructor
? "CreateInstance" : "Invoke",
1000 BindingFlags
.DeclaredOnly
|BindingFlags
.Public
|BindingFlags
.Instance
);
1001 if (this.member
== null){
1002 this.defaultMemberReturnIR
= Typeob
.ScriptFunction
;
1003 this.member
= this.defaultMemberReturnIR
.GetMethod(constructor
? "CreateInstance" : "Invoke",
1004 BindingFlags
.DeclaredOnly
|BindingFlags
.Public
|BindingFlags
.Instance
);
1008 // We have a script function but it might not be an "expando" function.
1009 if (constructor
&& this.members
.Length
!= 0 && this.members
[0] is JSFieldMethod
){
1010 JSFieldMethod fieldmethod
= (JSFieldMethod
)this.members
[0];
1011 fieldmethod
.func
.PartiallyEvaluate();
1012 if (!fieldmethod
.func
.isExpandoMethod
)
1013 this.context
.HandleError(JSError
.NotAnExpandoFunction
, this.isFullyResolved
);
1015 this.defaultMemberReturnIR
= t
;
1016 return this.member
= t
.GetMethod(constructor
? "CreateInstance" : "Invoke",
1017 BindingFlags
.DeclaredOnly
|BindingFlags
.Public
|BindingFlags
.Instance
);
1020 if (ir
== Typeob
.Type
){ //Type cast to type only known at runtime
1021 //Have to go late-bound
1025 if (ir
== Typeob
.Object
|| (ir
is ScriptObject
&& brackets
&& !(ir
is ClassScope
)))
1026 //The result of evaluating this binding could be a callable/constructable thing or a thing with a default indexed property.
1027 //Or it could not, but we don't know enough at compile time to moan about it.
1030 //Perhaps this is an array element access
1031 if (ir
is TypedArray
|| (ir
is Type
&& ((Type
)ir
).IsArray
)){
1032 int n
= argIRs
.Length
;
1033 int m
= ir
is TypedArray
? ((TypedArray
)ir
).rank
: ((Type
)ir
).GetArrayRank();
1035 this.context
.HandleError(JSError
.IncorrectNumberOfIndices
, this.isFullyResolved
);
1037 for (int i
= 0; i
< m
; i
++){
1038 if (argIRs
[i
] != Typeob
.Object
&& (!Convert
.IsPrimitiveNumericType(argIRs
[i
]) || Convert
.IsBadIndex(argList
[i
]))){
1039 argList
[i
].context
.HandleError(JSError
.TypeMismatch
, this.isFullyResolved
);
1045 if (!brackets
) goto ReportError
;
1046 //dealing with new Arr[...]. Give an error if the array element type is not Object, Type, or ScriptFunction
1047 IReflect elemIR
= ir
is TypedArray
? ((TypedArray
)ir
).elementType
: ((Type
)ir
).GetElementType();
1048 if (ir
!= Typeob
.Object
&& !(ir
is ClassScope
) &&
1049 !(ir
is Type
&& !Typeob
.Type
.IsAssignableFrom((Type
)ir
) && !Typeob
.ScriptFunction
.IsAssignableFrom((Type
)ir
)))
1052 this.isArrayElementAccess
= true;
1053 this.defaultMember
= member
;
1054 this.defaultMemberReturnIR
= ir
;
1055 return null; //Delay looking up the method to call until code gen time.
1058 //Perhaps The result of evaluating this binding is an object that has a default indexed property/method that can be called
1059 if (constructor
) goto ReportError
; //new binding(....) does not make sense for a default indexed property or method
1061 //Check for a default indexed property or default method
1062 if (brackets
&& ir
== Typeob
.String
&& (this.argIRs
.Length
!= 1 || !Convert
.IsPrimitiveNumericType(argIRs
[0])))
1063 ir
= Typeob
.StringObject
;
1064 MemberInfo
[] defaultMembers
= brackets
|| !(ir
is ScriptObject
) ? JSBinder
.GetDefaultMembers(ir
) : null;
1065 if (defaultMembers
!= null && defaultMembers
.Length
> 0){
1067 this.defaultMember
= member
;
1068 this.defaultMemberReturnIR
= ir
;
1069 return this.member
= JSBinder
.SelectMethod(this.members
= defaultMembers
, argIRs
); //Returns property getters as well
1070 }catch(AmbiguousMatchException
){
1071 this.context
.HandleError(JSError
.AmbiguousMatch
, this.isFullyResolved
);
1072 return this.member
= null;
1076 //Perhaps this is calling a delegate
1077 if (!brackets
&& ir
is Type
&& Typeob
.Delegate
.IsAssignableFrom((Type
)ir
)){
1078 this.defaultMember
= member
;
1079 this.defaultMemberReturnIR
= ir
;
1080 return this.member
= ((Type
)ir
).GetMethod("Invoke");
1084 //We now know enough to say that this binding really is not callable/constructable. Say so.
1086 this.context
.HandleError(JSError
.NeedType
, this.isFullyResolved
);
1088 this.context
.HandleError(JSError
.NotIndexable
, this.isFullyResolved
);
1090 this.context
.HandleError(JSError
.FunctionExpected
, this.isFullyResolved
);
1091 return this.member
= null;
1094 protected void ResolveRHValue(){
1095 MemberInfo member
= this.member
= LateBinding
.SelectMember(this.members
);
1096 JSLocalField lfield
= this.member
as JSLocalField
;
1097 if (lfield
!= null){
1098 FunctionObject funcOb
= lfield
.value as FunctionObject
;
1099 if (funcOb
!= null){
1100 FunctionScope enclosingScope
= funcOb
.enclosing_scope
as FunctionScope
;
1101 if (enclosingScope
!= null) enclosingScope
.closuresMightEscape
= true;
1104 if (member
is JSPrototypeField
){ //Have to go late bound
1108 if (!this.Accessible(false)){
1113 this.WarnIfNotFullyResolved();
1116 internal override void SetPartialValue(AST partial_value
){
1117 Binding
.AssignmentCompatible(this.InferType(null), partial_value
, partial_value
.InferType(null), this.isFullyResolved
);
1120 internal void SetPartialValue(ASTList argList
, IReflect
[] argIRs
, AST partial_value
, bool inBrackets
){
1121 if (this.members
== null || this.members
.Length
== 0){
1122 this.HandleNoSuchMemberError();
1123 this.isAssignmentToDefaultIndexedProperty
= true;
1124 return; //Have to do a runtime lookup
1127 this.PartiallyEvaluate(); //The rhside value of the binding delivers the object with the default indexed property we are assigning to
1128 IReflect ir
= this.InferType(null);
1129 this.isAssignmentToDefaultIndexedProperty
= true;
1130 if (ir
== Typeob
.Object
){
1131 JSVariableField jsvf
= this.member
as JSVariableField
;
1132 if (jsvf
== null || !jsvf
.IsLiteral
|| !(jsvf
.value is ClassScope
))
1133 return; //Not enough is known at compile time to give an error
1138 //Might be an assignment to an array element
1139 if ((ir
is TypedArray
|| (ir
is Type
&& ((Type
)ir
).IsArray
))){
1140 bool gaveAnError
= false;
1142 int n
= argIRs
.Length
;
1143 int m
= ir
is TypedArray
? ((TypedArray
)ir
).rank
: ((Type
)ir
).GetArrayRank();
1145 this.context
.HandleError(JSError
.IncorrectNumberOfIndices
, this.isFullyResolved
);
1148 //Check type of indices
1149 for (int i
= 0; i
< m
; i
++){
1150 if (!gaveAnError
&& i
< n
&& argIRs
[i
] != Typeob
.Object
&&
1151 (!Convert
.IsPrimitiveNumericType(argIRs
[i
]) || Convert
.IsBadIndex(argList
[i
]))){
1152 argList
[i
].context
.HandleError(JSError
.TypeMismatch
, this.isFullyResolved
);
1156 this.isArrayElementAccess
= true;
1157 this.isAssignmentToDefaultIndexedProperty
= false;
1158 this.defaultMember
= member
;
1159 this.defaultMemberReturnIR
= ir
;
1161 //Check type of rhside
1162 IReflect elemIR
= ir
is TypedArray
? ((TypedArray
)ir
).elementType
: ((Type
)ir
).GetElementType();
1163 Binding
.AssignmentCompatible(elemIR
, partial_value
, partial_value
.InferType(null), this.isFullyResolved
);
1167 //Might be an assignment to a default indexed property
1168 MemberInfo
[] defaultMembers
= JSBinder
.GetDefaultMembers(ir
);
1169 if (defaultMembers
!= null && defaultMembers
.Length
> 0 && this.member
!= null){
1171 PropertyInfo prop
= JSBinder
.SelectProperty(defaultMembers
, argIRs
);
1173 this.context
.HandleError(JSError
.NotIndexable
, Convert
.ToTypeName(ir
));
1176 if (JSProperty
.GetSetMethod(prop
, true) == null){
1177 if (ir
== Typeob
.String
)
1178 this.context
.HandleError(JSError
.UselessAssignment
);
1180 this.context
.HandleError(JSError
.AssignmentToReadOnly
, this.isFullyResolved
&&this.Engine
.doFast
);
1183 if (!Binding
.CheckParameters(prop
.GetIndexParameters(), argIRs
, argList
, this.context
, 0, false, true)){
1186 this.defaultMember
= this.member
;
1187 this.defaultMemberReturnIR
= ir
;
1188 this.members
= defaultMembers
;
1190 }catch(AmbiguousMatchException
){
1191 this.context
.HandleError(JSError
.AmbiguousMatch
, this.isFullyResolved
);
1200 this.context
.HandleError(JSError
.IllegalAssignment
);
1202 this.context
.HandleError(JSError
.NotIndexable
, Convert
.ToTypeName(ir
));
1205 internal override void SetValue(Object
value){
1206 MemberInfo member
= this.member
;
1207 Object ob
= this.GetObject();
1208 if (member
is FieldInfo
){
1209 FieldInfo field
= (FieldInfo
)member
;
1210 if (field
.IsLiteral
|| field
.IsInitOnly
) return;
1211 if (!(field
is JSField
) || field
is JSWrappedField
)
1212 value = Convert
.CoerceT(value, field
.FieldType
, false);
1213 field
.SetValue(ob
, value, BindingFlags
.SuppressChangeType
, null, null);
1216 if (member
is PropertyInfo
){
1217 PropertyInfo prop
= (PropertyInfo
)member
;
1218 if (ob
is ClassScope
&& !(prop
is JSProperty
)){
1219 JSProperty
.SetValue(prop
, ((WithObject
)((ClassScope
)ob
).GetParent()).contained_object
, value, null);
1222 if (!(prop
is JSProperty
))
1223 value = Convert
.CoerceT(value, prop
.PropertyType
, false);
1224 JSProperty
.SetValue(prop
, ob
, value, null);
1227 if (this.members
== null || this.members
.Length
== 0){
1228 this.EvaluateAsLateBinding().SetValue(value);
1231 //The name has been bound to something and that something is not a valid assignment target.
1232 throw new JScriptException(JSError
.IllegalAssignment
);
1235 internal override void TranslateToIL(ILGenerator il
, Type rtype
){
1236 this.TranslateToIL(il
, rtype
, false, false);
1239 internal void TranslateToIL(ILGenerator il
, Type rtype
, bool calledFromDelete
){
1240 this.TranslateToIL(il
, rtype
, false, false, calledFromDelete
);
1243 private void TranslateToIL(ILGenerator il
, Type rtype
, bool preSet
, bool preSetPlusGet
){
1244 this.TranslateToIL(il
, rtype
, preSet
, preSetPlusGet
, false);
1247 private void TranslateToIL(ILGenerator il
, Type rtype
, bool preSet
, bool preSetPlusGet
, bool calledFromDelete
){
1248 if (this.member
is FieldInfo
){
1249 FieldInfo field
= (FieldInfo
)this.member
;
1250 bool isStatic
= field
.IsStatic
|| field
.IsLiteral
;
1251 if (field
.IsLiteral
&& field
is JSMemberField
){
1252 Object val
= ((JSMemberField
)field
).value;
1253 FunctionObject func
= val
as FunctionObject
;
1254 isStatic
= func
== null || !func
.isExpandoMethod
;
1256 if (!isStatic
|| field
is JSClosureField
){
1257 this.TranslateToILObject(il
, field
.DeclaringType
, true);
1259 il
.Emit(OpCodes
.Dup
);
1263 Object tok
= field
is JSField
? ((JSField
)field
).GetMetaData() : field
is JSFieldInfo
? ((JSFieldInfo
)field
).field
: field
;
1264 if (tok
is FieldInfo
&& !((FieldInfo
)tok
).IsLiteral
)
1265 il
.Emit(isStatic
? OpCodes
.Ldsfld
: OpCodes
.Ldfld
, (FieldInfo
)tok
);
1266 else if (tok
is LocalBuilder
)
1267 il
.Emit(OpCodes
.Ldloc
, (LocalBuilder
)tok
);
1268 else if (field
.IsLiteral
){
1269 (new ConstantWrapper(TypeReferences
.GetConstantValue(field
), this.context
)).TranslateToIL(il
, rtype
);
1272 Convert
.EmitLdarg(il
, (short)tok
);
1273 Convert
.Emit(this, il
, field
.FieldType
, rtype
);
1277 if (this.member
is PropertyInfo
){
1278 PropertyInfo prop
= (PropertyInfo
)this.member
;
1279 MethodInfo meth
= preSet
? JSProperty
.GetSetMethod(prop
, true) : JSProperty
.GetGetMethod(prop
, true);
1282 if (this is Lookup
){
1283 il
.Emit(OpCodes
.Ldc_I4
, (int)JSError
.WriteOnlyProperty
);
1284 il
.Emit(OpCodes
.Newobj
, CompilerGlobals
.scriptExceptionConstructor
);
1285 il
.Emit(OpCodes
.Throw
);
1287 il
.Emit(OpCodes
.Ldnull
);
1290 bool isStatic
= meth
.IsStatic
&& !(meth
is JSClosureMethod
);
1292 Type obType
= meth
.DeclaringType
;
1293 if (obType
== Typeob
.StringObject
&& meth
.Name
.Equals("get_length")){
1294 this.TranslateToILObject(il
, Typeob
.String
, false);
1295 meth
= CompilerGlobals
.stringLengthMethod
;
1297 this.TranslateToILObject(il
, obType
, true);
1300 Debug
.Assert(meth
.GetParameters().Length
== 0);
1301 meth
= this.GetMethodInfoMetadata(meth
);
1303 il
.Emit(OpCodes
.Call
, meth
);
1306 il
.Emit(OpCodes
.Dup
);
1307 if (!this.isNonVirtual
&& meth
.IsVirtual
&& !meth
.IsFinal
&& (!meth
.ReflectedType
.IsSealed
|| !meth
.ReflectedType
.IsValueType
))
1308 il
.Emit(OpCodes
.Callvirt
, meth
);
1310 il
.Emit(OpCodes
.Call
, meth
);
1312 Convert
.Emit(this, il
, meth
.ReturnType
, rtype
);
1316 if (this.member
is MethodInfo
){
1317 MethodInfo meth
= this.GetMethodInfoMetadata((MethodInfo
)this.member
);
1318 if (Typeob
.Delegate
.IsAssignableFrom(rtype
)){
1319 if (!meth
.IsStatic
){
1320 Type obType
= meth
.DeclaringType
;
1321 this.TranslateToILObject(il
, obType
, false);
1322 if (obType
.IsValueType
)
1323 il
.Emit(OpCodes
.Box
, obType
);
1325 il
.Emit(OpCodes
.Ldnull
);
1326 if (meth
.IsVirtual
&& !meth
.IsFinal
&& (!meth
.ReflectedType
.IsSealed
|| !meth
.ReflectedType
.IsValueType
)){
1327 il
.Emit(OpCodes
.Dup
);
1328 il
.Emit(OpCodes
.Ldvirtftn
, meth
);
1330 il
.Emit(OpCodes
.Ldftn
, meth
);
1331 ConstructorInfo cons
= rtype
.GetConstructor(new Type
[]{Typeob.Object, Typeob.UIntPtr}
);
1332 if (cons
== null) cons
= rtype
.GetConstructor(new Type
[]{Typeob.Object, Typeob.IntPtr}
);
1333 il
.Emit(OpCodes
.Newobj
, cons
);
1336 //ResolveRHValue will never set this.member to a MethodInfo. The above case only happens
1337 //because IsCompatibleWithDelegate sets this.member to the method that matches the delegate type.
1338 if (member
is JSExpandoIndexerMethod
){
1339 //Need to put the expando class instance on the stack as the this object in expressions such as exInstance["foo"]90
1340 MemberInfo mem
= this.member
;
1341 this.member
= this.defaultMember
;
1342 this.TranslateToIL(il
, Typeob
.Object
);
1346 il
.Emit(OpCodes
.Ldnull
); //get something on the stack, in case we DO get here
1347 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
1352 ((Lookup
)this).TranslateToLateBinding(il
);
1354 if (!this.isFullyResolved
&& !preSet
&& !preSetPlusGet
)
1355 done
= this.TranslateToSpeculativeEarlyBindings(il
, rtype
, false);
1356 ((Member
)this).TranslateToLateBinding(il
, done
!= null);
1357 if (!this.isFullyResolved
&& preSetPlusGet
)
1358 done
= this.TranslateToSpeculativeEarlyBindings(il
, rtype
, true);
1361 il
.Emit(OpCodes
.Dup
);
1363 if (this is Lookup
&& !calledFromDelete
)
1364 il
.Emit(OpCodes
.Call
, CompilerGlobals
.getValue2Method
);
1366 il
.Emit(OpCodes
.Call
, CompilerGlobals
.getNonMissingValueMethod
);
1367 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
1369 il
.MarkLabel((Label
)done
);
1373 internal override void TranslateToILCall(ILGenerator il
, Type rtype
, ASTList argList
, bool construct
, bool brackets
){
1374 MemberInfo member
= this.member
;
1375 if (this.defaultMember
!= null){
1376 if (this.isArrayConstructor
){
1377 TypedArray tArr
= (TypedArray
)this.defaultMemberReturnIR
;
1378 Type eType
= Convert
.ToType(tArr
.elementType
);
1379 Debug
.Assert(tArr
.rank
== argList
.count
);
1382 argList
[0].TranslateToIL(il
, Typeob
.Int32
);
1383 il
.Emit(OpCodes
.Newarr
, eType
);
1385 Type aType
= tArr
.ToType();
1386 Type
[] dTypes
= new Type
[r
];
1387 for (int i
= 0; i
< r
; i
++) dTypes
[i
] = Typeob
.Int32
;
1388 for (int i
= 0, n
= argList
.count
; i
< n
; i
++)
1389 argList
[i
].TranslateToIL(il
, Typeob
.Int32
);
1390 TypeBuilder eTypeB
= eType
as TypeBuilder
;
1391 if (eTypeB
!= null){
1392 MethodInfo cons
= ((ModuleBuilder
)aType
.Module
).GetArrayMethod(aType
, ".ctor", CallingConventions
.HasThis
, Typeob
.Void
, dTypes
);
1393 il
.Emit(OpCodes
.Newobj
, cons
);
1395 ConstructorInfo cons
= aType
.GetConstructor(dTypes
);
1396 il
.Emit(OpCodes
.Newobj
, cons
);
1399 Convert
.Emit(this, il
, tArr
.ToType(), rtype
);
1402 this.member
= this.defaultMember
;
1403 IReflect defIR
= this.defaultMemberReturnIR
;
1404 Type defType
= defIR
is Type
? (Type
)defIR
: Convert
.ToType(defIR
);
1405 this.TranslateToIL(il
, defType
);
1406 if (this.isArrayElementAccess
){
1407 Debug
.Assert(defType
.IsArray
);
1408 for (int i
= 0, m
= argList
.count
; i
< m
; i
++)
1409 argList
[i
].TranslateToIL(il
, Typeob
.Int32
);
1410 Type etype
= defType
.GetElementType();
1411 int n
= defType
.GetArrayRank();
1413 Binding
.TranslateToLdelem(il
, etype
);
1415 Type
[] indexTypes
= new Type
[n
];
1416 for (int i
= 0; i
< n
; i
++) indexTypes
[i
] = Typeob
.Int32
;
1417 MethodInfo getter
= compilerGlobals
.module
.GetArrayMethod(defType
, "Get", CallingConventions
.HasThis
, etype
, indexTypes
);
1418 il
.Emit(OpCodes
.Call
, getter
);
1420 Convert
.Emit(this, il
, etype
, rtype
);
1423 this.member
= member
;
1425 if (member
is MethodInfo
){
1426 MethodInfo meth
= (MethodInfo
)member
;
1427 Type dt
= meth
.DeclaringType
;
1428 Type rt
= meth
.ReflectedType
;
1429 ParameterInfo
[] pars
= meth
.GetParameters();
1430 bool isStatic
= meth
.IsStatic
;
1431 if (!isStatic
&& this.defaultMember
== null)
1432 this.TranslateToILObject(il
, dt
, true);
1433 if (meth
is JSClosureMethod
)
1434 this.TranslateToILObject(il
, dt
, false);
1435 ConstantWrapper missing
= null;
1437 if (meth
is JSFieldMethod
|| CustomAttribute
.IsDefined(meth
, typeof(JSFunctionAttribute
), false)){
1438 offset
= this.PlaceValuesForHiddenParametersOnStack(il
, meth
, pars
);
1439 missing
= Binding
.JScriptMissingCW
;
1441 missing
= Binding
.ReflectionMissingCW
;
1442 if (argList
.count
== 1 && missing
== Binding
.JScriptMissingCW
&& this.defaultMember
is PropertyInfo
){
1443 //Dealing with the CreateInstance method of a constructor function
1444 Debug
.Assert(meth
.Name
== "CreateInstance" || meth
.Name
== "Invoke");
1445 il
.Emit(OpCodes
.Ldc_I4_1
);
1446 il
.Emit(OpCodes
.Newarr
, Typeob
.Object
);
1447 il
.Emit(OpCodes
.Dup
);
1448 il
.Emit(OpCodes
.Ldc_I4_0
);
1449 argList
[0].TranslateToIL(il
, Typeob
.Object
);
1450 il
.Emit(OpCodes
.Stelem_Ref
);
1452 Binding
.PlaceArgumentsOnStack(il
, pars
, argList
, offset
, 0, missing
);
1453 meth
= this.GetMethodInfoMetadata(meth
);
1454 if (!this.isNonVirtual
&& meth
.IsVirtual
&& !meth
.IsFinal
&& (!rt
.IsSealed
|| !rt
.IsValueType
))
1455 il
.Emit(OpCodes
.Callvirt
, meth
);
1457 il
.Emit(OpCodes
.Call
, meth
);
1458 Convert
.Emit(this, il
, meth
.ReturnType
, rtype
);
1461 if (member
is ConstructorInfo
){
1462 Debug
.Assert(construct
);
1463 ConstructorInfo cons
= (ConstructorInfo
)member
;
1464 ParameterInfo
[] pars
= cons
.GetParameters();
1465 bool instanceNestedClassConstructor
= false;
1466 if (CustomAttribute
.IsDefined(cons
, typeof(JSFunctionAttribute
), false)){
1467 Object
[] attrs
= CustomAttribute
.GetCustomAttributes(cons
, typeof(JSFunctionAttribute
), false);
1468 instanceNestedClassConstructor
= (((JSFunctionAttribute
)attrs
[0]).attributeValue
& JSFunctionAttributeEnum
.IsInstanceNestedClassConstructor
) != 0;
1470 if (instanceNestedClassConstructor
){
1471 Binding
.PlaceArgumentsOnStack(il
, pars
, argList
, 0, 1, Binding
.ReflectionMissingCW
);
1472 this.TranslateToILObject(il
, pars
[pars
.Length
-1].ParameterType
, false);
1474 Binding
.PlaceArgumentsOnStack(il
, pars
, argList
, 0, 0, Binding
.ReflectionMissingCW
);
1475 Type outerClass
= null;
1476 if (member
is JSConstructor
&& (outerClass
= ((JSConstructor
)member
).OuterClassType()) != null)
1477 this.TranslateToILObject(il
, outerClass
, false);
1478 bool needEngine
= false;
1479 Type t
= cons
.DeclaringType
;
1480 if (cons
is JSConstructor
){
1481 cons
= ((JSConstructor
)cons
).GetConstructorInfo(compilerGlobals
);
1484 needEngine
= Typeob
.INeedEngine
.IsAssignableFrom(t
);
1485 il
.Emit(OpCodes
.Newobj
, cons
);
1487 il
.Emit(OpCodes
.Dup
);
1488 this.EmitILToLoadEngine(il
);
1489 il
.Emit(OpCodes
.Callvirt
, CompilerGlobals
.setEngineMethod
);
1491 Convert
.Emit(this, il
, t
, rtype
);
1494 Type mt
= member
as Type
;
1496 Debug
.Assert(!construct
&& !brackets
);
1497 Debug
.Assert(argList
.count
== 1);
1498 AST arg0
= argList
[0];
1499 if (arg0
is NullLiteral
){ //Skip the double conversion path below that involves runtime helper
1500 arg0
.TranslateToIL(il
, mt
);
1501 Convert
.Emit(this, il
, mt
, rtype
);
1504 IReflect arg0ir
= arg0
.InferType(null);
1505 if (arg0ir
== Typeob
.ScriptFunction
&& Typeob
.Delegate
.IsAssignableFrom(mt
))
1506 arg0
.TranslateToIL(il
, mt
);
1508 Type argType
= Convert
.ToType(arg0ir
);
1509 arg0
.TranslateToIL(il
, argType
);
1510 Convert
.Emit(this, il
, argType
, mt
, true);
1512 Convert
.Emit(this, il
, mt
, rtype
);
1515 if (member
is FieldInfo
&& ((FieldInfo
)member
).IsLiteral
){
1516 Object val
= member
is JSVariableField
? ((JSVariableField
)member
).value : TypeReferences
.GetConstantValue((FieldInfo
)member
);
1517 if (val
is Type
|| val
is ClassScope
|| val
is TypedArray
){
1518 Debug
.Assert(argList
.count
== 1);
1519 AST arg0
= argList
[0];
1520 if (arg0
is NullLiteral
){
1521 il
.Emit(OpCodes
.Ldnull
);
1524 ClassScope csc
= val
as ClassScope
;
1526 EnumDeclaration ed
= csc
.owner
as EnumDeclaration
;
1528 val
= ed
.baseType
.ToType();
1530 Type argType
= Convert
.ToType(arg0
.InferType(null));
1531 arg0
.TranslateToIL(il
, argType
);
1532 Type t
= val
is Type
? (Type
)val
: val
is ClassScope
? Convert
.ToType((ClassScope
)val
) : ((TypedArray
)val
).ToType();
1533 Convert
.Emit(this, il
, argType
, t
, true);
1535 Convert
.Emit(this, il
, t
, rtype
);
1539 LocalBuilder loc
= null;
1540 for (int i
= 0, n
= argList
.count
; i
< n
; i
++){
1541 if (argList
[i
] is AddressOf
){
1542 loc
= il
.DeclareLocal(Typeob
.ArrayOfObject
);
1547 if (member
== null && (this.members
== null || this.members
.Length
== 0)){
1549 ((Lookup
)this).TranslateToLateBinding(il
);
1551 done
= this.TranslateToSpeculativeEarlyBoundCalls(il
, rtype
, argList
, construct
, brackets
);
1552 ((Member
)this).TranslateToLateBinding(il
, done
!= null);
1554 argList
.TranslateToIL(il
, Typeob
.ArrayOfObject
);
1556 il
.Emit(OpCodes
.Dup
);
1557 il
.Emit(OpCodes
.Stloc
, loc
);
1560 il
.Emit(OpCodes
.Ldc_I4_1
);
1562 il
.Emit(OpCodes
.Ldc_I4_0
);
1564 il
.Emit(OpCodes
.Ldc_I4_1
);
1566 il
.Emit(OpCodes
.Ldc_I4_0
);
1567 this.EmitILToLoadEngine(il
);
1568 il
.Emit(OpCodes
.Call
, CompilerGlobals
.callMethod
);
1569 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
1571 for (int i
= 0, n
= argList
.count
; i
< n
; i
++){
1572 AddressOf addr
= argList
[i
] as AddressOf
;
1574 addr
.TranslateToILPreSet(il
);
1575 il
.Emit(OpCodes
.Ldloc
, loc
);
1576 ConstantWrapper
.TranslateToILInt(il
, i
);
1577 il
.Emit(OpCodes
.Ldelem_Ref
);
1578 Convert
.Emit(this, il
, Typeob
.Object
, Convert
.ToType(addr
.InferType(null)));
1579 addr
.TranslateToILSet(il
, null);
1584 il
.MarkLabel((Label
)done
);
1587 this.TranslateToILWithDupOfThisOb(il
);
1588 argList
.TranslateToIL(il
, Typeob
.ArrayOfObject
);
1590 il
.Emit(OpCodes
.Dup
);
1591 il
.Emit(OpCodes
.Stloc
, loc
);
1594 il
.Emit(OpCodes
.Ldc_I4_1
);
1596 il
.Emit(OpCodes
.Ldc_I4_0
);
1598 il
.Emit(OpCodes
.Ldc_I4_1
);
1600 il
.Emit(OpCodes
.Ldc_I4_0
);
1601 this.EmitILToLoadEngine(il
);
1602 il
.Emit(OpCodes
.Call
, CompilerGlobals
.callValueMethod
);
1603 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
1605 for (int i
= 0, n
= argList
.count
; i
< n
; i
++){
1606 AddressOf addr
= argList
[i
] as AddressOf
;
1608 addr
.TranslateToILPreSet(il
);
1609 il
.Emit(OpCodes
.Ldloc
, loc
);
1610 ConstantWrapper
.TranslateToILInt(il
, i
);
1611 il
.Emit(OpCodes
.Ldelem_Ref
);
1612 Convert
.Emit(this, il
, Typeob
.Object
, Convert
.ToType(addr
.InferType(null)));
1613 addr
.TranslateToILSet(il
, null);
1619 internal override void TranslateToILDelete(ILGenerator il
, Type rtype
){
1621 ((Lookup
)this).TranslateToLateBinding(il
);
1623 ((Member
)this).TranslateToLateBinding(il
, false);
1624 il
.Emit(OpCodes
.Call
, CompilerGlobals
.deleteMethod
);
1625 Convert
.Emit(this, il
, Typeob
.Boolean
, rtype
);
1628 protected abstract void TranslateToILObject(ILGenerator il
, Type obtype
, bool noValue
);
1630 internal override void TranslateToILPreSet(ILGenerator il
){
1631 this.TranslateToIL(il
, null, true, false);
1634 internal override void TranslateToILPreSet(ILGenerator il
, ASTList argList
){
1635 if (this.isArrayElementAccess
){
1636 this.member
= this.defaultMember
;
1637 IReflect defIR
= this.defaultMemberReturnIR
;
1638 Type defType
= defIR
is Type
? (Type
)defIR
: Convert
.ToType(defIR
);
1639 this.TranslateToIL(il
, defType
);
1640 Debug
.Assert(defType
.IsArray
);
1641 for (int i
= 0, m
= argList
.count
; i
< m
; i
++)
1642 argList
[i
].TranslateToIL(il
, Typeob
.Int32
);
1643 if (defType
.GetArrayRank() == 1){
1644 Type etype
= defType
.GetElementType();
1645 if (etype
.IsValueType
&& !etype
.IsPrimitive
&& !etype
.IsEnum
)
1646 il
.Emit(OpCodes
.Ldelema
, etype
);
1650 Debug
.Assert(this.isAssignmentToDefaultIndexedProperty
);
1651 if (this.member
is PropertyInfo
&& this.defaultMember
!= null){ //early bound to default indexed property
1652 PropertyInfo prop
= (PropertyInfo
)this.member
;
1653 this.member
= this.defaultMember
;
1654 this.TranslateToIL(il
, Convert
.ToType(this.defaultMemberReturnIR
));
1656 Binding
.PlaceArgumentsOnStack(il
, prop
.GetIndexParameters(), argList
, 0, 0, Binding
.ReflectionMissingCW
);
1659 base.TranslateToILPreSet(il
, argList
);
1662 internal override void TranslateToILPreSetPlusGet(ILGenerator il
){
1663 this.TranslateToIL(il
, Convert
.ToType(this.InferType(null)), false, true);
1666 internal override void TranslateToILPreSetPlusGet(ILGenerator il
, ASTList argList
, bool inBrackets
){
1667 if (this.isArrayElementAccess
){
1668 this.member
= this.defaultMember
;
1669 IReflect defIR
= this.defaultMemberReturnIR
;
1670 Type defType
= defIR
is Type
? (Type
)defIR
: Convert
.ToType(defIR
);
1671 Debug
.Assert(defType
.IsArray
);
1672 this.TranslateToIL(il
, defType
);
1673 il
.Emit(OpCodes
.Dup
);
1674 int n
= defType
.GetArrayRank();
1675 LocalBuilder
[] iTemp
= new LocalBuilder
[n
];
1676 for (int i
= 0, m
= argList
.count
; i
< m
; i
++){
1677 argList
[i
].TranslateToIL(il
, Typeob
.Int32
);
1678 iTemp
[i
] = il
.DeclareLocal(Typeob
.Int32
);
1679 il
.Emit(OpCodes
.Dup
);
1680 il
.Emit(OpCodes
.Stloc
, iTemp
[i
]);
1682 Type etype
= defType
.GetElementType();
1684 Binding
.TranslateToLdelem(il
, etype
);
1686 Type
[] indexTypes
= new Type
[n
];
1687 for (int i
= 0; i
< n
; i
++) indexTypes
[i
] = Typeob
.Int32
;
1688 MethodInfo getter
= defType
.GetMethod("Get", indexTypes
);
1689 il
.Emit(OpCodes
.Call
, getter
);
1691 LocalBuilder eTemp
= il
.DeclareLocal(etype
);
1692 il
.Emit(OpCodes
.Stloc
, eTemp
);
1693 for (int i
= 0; i
< n
; i
++)
1694 il
.Emit(OpCodes
.Ldloc
, iTemp
[i
]);
1695 if (n
== 1 && etype
.IsValueType
&& !etype
.IsPrimitive
)
1696 il
.Emit(OpCodes
.Ldelema
, etype
);
1697 il
.Emit(OpCodes
.Ldloc
, eTemp
);
1700 Debug
.Assert(this.isAssignmentToDefaultIndexedProperty
);
1701 if (this.member
!= null){
1702 //Go late bound. It is too much work, for too little gain, to do this early bound
1703 if (this.defaultMember
!= null){
1704 this.member
= this.defaultMember
;
1705 this.defaultMember
= null;
1708 base.TranslateToILPreSetPlusGet(il
, argList
, inBrackets
);
1711 internal override Object
TranslateToILReference(ILGenerator il
, Type rtype
){
1712 if (this.member
is FieldInfo
){
1713 FieldInfo field
= (FieldInfo
)this.member
;
1714 Type ftype
= field
.FieldType
;
1715 if (rtype
== ftype
){
1716 bool isStatic
= field
.IsStatic
;
1718 this.TranslateToILObject(il
, field
.DeclaringType
, true);
1719 Object tok
= field
is JSField
? ((JSField
)field
).GetMetaData() : field
is JSFieldInfo
? ((JSFieldInfo
)field
).field
: field
;
1720 if (tok
is FieldInfo
)
1721 if (field
.IsInitOnly
){
1722 LocalBuilder loc
= il
.DeclareLocal(ftype
);
1723 il
.Emit(isStatic
? OpCodes
.Ldsfld
: OpCodes
.Ldfld
, (FieldInfo
)tok
);
1724 il
.Emit(OpCodes
.Stloc
, loc
);
1725 il
.Emit(OpCodes
.Ldloca
, loc
);
1727 il
.Emit(isStatic
? OpCodes
.Ldsflda
: OpCodes
.Ldflda
, (FieldInfo
)tok
);
1728 else if (tok
is LocalBuilder
)
1729 il
.Emit(OpCodes
.Ldloca
, (LocalBuilder
)tok
);
1731 il
.Emit(OpCodes
.Ldarga
, (short)tok
);
1735 return base.TranslateToILReference(il
, rtype
);
1738 internal override void TranslateToILSet(ILGenerator il
, AST rhvalue
){
1739 if (this.isArrayElementAccess
){
1740 IReflect defIR
= this.defaultMemberReturnIR
;
1741 Type defType
= defIR
is Type
? (Type
)defIR
: Convert
.ToType(defIR
);
1742 Debug
.Assert(defType
.IsArray
);
1743 int n
= defType
.GetArrayRank();
1744 Type etype
= defType
.GetElementType();
1745 if (rhvalue
!= null)
1746 rhvalue
.TranslateToIL(il
, etype
);
1748 Binding
.TranslateToStelem(il
, etype
);
1750 Type
[] indexTypes
= new Type
[n
+1];
1751 for (int i
= 0; i
< n
; i
++) indexTypes
[i
] = Typeob
.Int32
;
1752 indexTypes
[n
] = etype
;
1753 MethodInfo setter
= compilerGlobals
.module
.GetArrayMethod(defType
, "Set", CallingConventions
.HasThis
, Typeob
.Void
, indexTypes
);
1754 il
.Emit(OpCodes
.Call
, setter
);
1758 if (this.isAssignmentToDefaultIndexedProperty
){
1759 if (this.member
is PropertyInfo
&& this.defaultMember
!= null){ //early bound to default indexed property
1760 PropertyInfo prop
= (PropertyInfo
)this.member
;
1761 MethodInfo meth
= JSProperty
.GetSetMethod(prop
, false);
1762 //Guard against trying to assign to properties on the Global object
1763 JSWrappedMethod wmeth
= meth
as JSWrappedMethod
;
1764 if (wmeth
== null || !(wmeth
.GetWrappedObject() is GlobalObject
)){
1765 meth
= this.GetMethodInfoMetadata(meth
);
1766 if (rhvalue
!= null)
1767 rhvalue
.TranslateToIL(il
, prop
.PropertyType
);
1768 if (meth
.IsVirtual
&& !meth
.IsFinal
&& (!meth
.ReflectedType
.IsSealed
|| !meth
.ReflectedType
.IsValueType
))
1769 il
.Emit(OpCodes
.Callvirt
, meth
);
1771 il
.Emit(OpCodes
.Call
, meth
);
1775 base.TranslateToILSet(il
, rhvalue
);
1778 if (this.member
is FieldInfo
){
1779 FieldInfo field
= (FieldInfo
)this.member
;
1780 if (rhvalue
!= null)
1781 rhvalue
.TranslateToIL(il
, field
.FieldType
);
1782 if (field
.IsLiteral
|| field
.IsInitOnly
){
1783 il
.Emit(OpCodes
.Pop
);
1786 Object tok
= field
is JSField
? ((JSField
)field
).GetMetaData() : field
is JSFieldInfo
? ((JSFieldInfo
)field
).field
: field
;
1787 FieldInfo f
= tok
as FieldInfo
;
1789 il
.Emit(f
.IsStatic
? OpCodes
.Stsfld
: OpCodes
.Stfld
, f
);
1790 else if (tok
is LocalBuilder
)
1791 il
.Emit(OpCodes
.Stloc
, (LocalBuilder
)tok
);
1793 il
.Emit(OpCodes
.Starg
, (short)tok
);
1796 if (this.member
is PropertyInfo
){
1797 PropertyInfo prop
= (PropertyInfo
)this.member
;
1798 if (rhvalue
!= null)
1799 rhvalue
.TranslateToIL(il
, prop
.PropertyType
);
1800 MethodInfo meth
= JSProperty
.GetSetMethod(prop
, true);
1802 il
.Emit(OpCodes
.Pop
);
1805 meth
= this.GetMethodInfoMetadata(meth
);
1806 if (meth
.IsStatic
&& !(meth
is JSClosureMethod
))
1807 il
.Emit(OpCodes
.Call
, meth
);
1809 if (!this.isNonVirtual
&& meth
.IsVirtual
&& !meth
.IsFinal
&& (!meth
.ReflectedType
.IsSealed
|| !meth
.ReflectedType
.IsValueType
))
1810 il
.Emit(OpCodes
.Callvirt
, meth
);
1812 il
.Emit(OpCodes
.Call
, meth
);
1816 //do speculative early bound assignments
1817 Object done
= this.TranslateToSpeculativeEarlyBoundSet(il
, rhvalue
);
1818 if (rhvalue
!= null)
1819 rhvalue
.TranslateToIL(il
, Typeob
.Object
);
1820 il
.Emit(OpCodes
.Call
, CompilerGlobals
.setValueMethod
);
1822 il
.MarkLabel((Label
)done
);
1825 protected abstract void TranslateToILWithDupOfThisOb(ILGenerator il
);
1827 private static void TranslateToLdelem(ILGenerator il
, Type etype
){
1828 switch(Type
.GetTypeCode(etype
)){
1829 case TypeCode
.SByte
:
1830 il
.Emit(OpCodes
.Ldelem_I1
); break;
1831 case TypeCode
.Boolean
:
1833 il
.Emit(OpCodes
.Ldelem_U1
); break;
1834 case TypeCode
.Int16
:
1835 il
.Emit(OpCodes
.Ldelem_I2
); break;
1837 case TypeCode
.UInt16
:
1838 il
.Emit(OpCodes
.Ldelem_U2
); break;
1839 case TypeCode
.Int32
:
1840 il
.Emit(OpCodes
.Ldelem_I4
); break;
1841 case TypeCode
.UInt32
:
1842 il
.Emit(OpCodes
.Ldelem_U4
); break;
1843 case TypeCode
.Int64
:
1844 case TypeCode
.UInt64
:
1845 il
.Emit(OpCodes
.Ldelem_I8
); break;
1846 case TypeCode
.Single
:
1847 il
.Emit(OpCodes
.Ldelem_R4
); break;
1848 case TypeCode
.Double
:
1849 il
.Emit(OpCodes
.Ldelem_R8
); break;
1850 case TypeCode
.Decimal
:
1851 case TypeCode
.DateTime
:
1852 case TypeCode
.String
:
1853 case TypeCode
.Object
:
1854 if (etype
.IsValueType
){
1855 il
.Emit(OpCodes
.Ldelema
, etype
);
1856 il
.Emit(OpCodes
.Ldobj
, etype
);
1858 il
.Emit(OpCodes
.Ldelem_Ref
);
1863 private Object
TranslateToSpeculativeEarlyBoundSet(ILGenerator il
, AST rhvalue
){
1864 this.giveErrors
= false;
1866 bool needObject
= true;
1867 LocalBuilder objectLocal
= null;
1868 LocalBuilder valueLocal
= null;
1869 Label next
= il
.DefineLabel();
1870 MemberInfoList members
= this.GetAllKnownInstanceBindingsForThisName();
1871 for (int i
= 0, n
= members
.count
; i
< n
; i
++){
1872 MemberInfo member
= members
[i
];
1873 FieldInfo field
= null;
1874 MethodInfo setter
= null;
1875 PropertyInfo prop
= null;
1876 if (member
is FieldInfo
){
1877 field
= (FieldInfo
)member
;
1878 if (field
.IsLiteral
|| field
.IsInitOnly
) continue;
1879 }else if (member
is PropertyInfo
){
1880 prop
= (PropertyInfo
)member
;
1881 if (prop
.GetIndexParameters().Length
> 0 ||
1882 (setter
= JSProperty
.GetSetMethod(prop
, true)) == null) continue;
1885 this.member
= member
;
1886 if (!this.Accessible(true)) continue;
1889 if (rhvalue
== null){
1890 valueLocal
= il
.DeclareLocal(Typeob
.Object
);
1891 il
.Emit(OpCodes
.Stloc
, valueLocal
);
1893 il
.Emit(OpCodes
.Dup
);
1894 il
.Emit(OpCodes
.Ldfld
, CompilerGlobals
.objectField
);
1895 objectLocal
= il
.DeclareLocal(Typeob
.Object
);
1896 il
.Emit(OpCodes
.Stloc
, objectLocal
);
1897 done
= il
.DefineLabel();
1899 Type t
= member
.DeclaringType
;
1900 il
.Emit(OpCodes
.Ldloc
, objectLocal
);
1901 il
.Emit(OpCodes
.Isinst
, t
);
1902 LocalBuilder objectTemp
= il
.DeclareLocal(t
);
1903 il
.Emit(OpCodes
.Dup
);
1904 il
.Emit(OpCodes
.Stloc
, objectTemp
);
1905 il
.Emit(OpCodes
.Brfalse
, next
);
1906 il
.Emit(OpCodes
.Ldloc
, objectTemp
);
1907 if (rhvalue
== null)
1908 il
.Emit(OpCodes
.Ldloc
, valueLocal
);
1910 if (rhvalue
== null)
1911 Convert
.Emit(this, il
, Typeob
.Object
, field
.FieldType
);
1913 rhvalue
.TranslateToIL(il
, field
.FieldType
);
1914 if (field
is JSField
)
1915 il
.Emit(OpCodes
.Stfld
, (FieldInfo
)((JSField
)field
).GetMetaData());
1916 else if (field
is JSFieldInfo
)
1917 il
.Emit(OpCodes
.Stfld
, ((JSFieldInfo
)field
).field
);
1919 il
.Emit(OpCodes
.Stfld
, field
);
1921 if (rhvalue
== null)
1922 Convert
.Emit(this, il
, Typeob
.Object
, prop
.PropertyType
);
1924 rhvalue
.TranslateToIL(il
, prop
.PropertyType
);
1925 setter
= this.GetMethodInfoMetadata(setter
);
1926 if (setter
.IsVirtual
&& !setter
.IsFinal
&& (!t
.IsSealed
|| !t
.IsValueType
))
1927 il
.Emit(OpCodes
.Callvirt
, setter
);
1929 il
.Emit(OpCodes
.Call
, setter
);
1931 il
.Emit(OpCodes
.Pop
); //Get rid of the LateBound instance
1932 il
.Emit(OpCodes
.Br
, (Label
)done
);
1934 next
= il
.DefineLabel();
1936 if (valueLocal
!= null)
1937 il
.Emit(OpCodes
.Ldloc
, valueLocal
);
1942 private Object
TranslateToSpeculativeEarlyBindings(ILGenerator il
, Type rtype
, bool getObjectFromLateBindingInstance
){
1943 //Find all members named this.name to which the current context might have access to.
1944 //Generate early bound access to these, guarded by runtime type checks.
1945 this.giveErrors
= false;
1947 bool needObject
= true;
1948 LocalBuilder objectLocal
= null;
1949 Label next
= il
.DefineLabel();
1950 MemberInfoList members
= this.GetAllKnownInstanceBindingsForThisName();
1951 for (int i
= 0, n
= members
.count
; i
< n
; i
++){
1952 MemberInfo member
= members
[i
];
1953 if (!(member
is FieldInfo
) && (!(member
is PropertyInfo
) ||
1954 ((PropertyInfo
)member
).GetIndexParameters().Length
> 0 ||
1955 JSProperty
.GetGetMethod((PropertyInfo
)member
, true) == null)) continue;
1956 this.member
= member
;
1957 if (!this.Accessible(false)) continue;
1960 if (getObjectFromLateBindingInstance
){
1961 il
.Emit(OpCodes
.Dup
);
1962 il
.Emit(OpCodes
.Ldfld
, CompilerGlobals
.objectField
);
1964 this.TranslateToILObject(il
, Typeob
.Object
, false);
1965 objectLocal
= il
.DeclareLocal(Typeob
.Object
);
1966 il
.Emit(OpCodes
.Stloc
, objectLocal
);
1967 done
= il
.DefineLabel();
1969 Type t
= member
.DeclaringType
;
1970 il
.Emit(OpCodes
.Ldloc
, objectLocal
);
1971 il
.Emit(OpCodes
.Isinst
, t
);
1972 LocalBuilder objectTemp
= il
.DeclareLocal(t
);
1973 il
.Emit(OpCodes
.Dup
);
1974 il
.Emit(OpCodes
.Stloc
, objectTemp
);
1975 il
.Emit(OpCodes
.Brfalse_S
, next
);
1976 il
.Emit(OpCodes
.Ldloc
, objectTemp
);
1977 if (member
is FieldInfo
){
1978 FieldInfo field
= (FieldInfo
)member
;
1979 if (field
.IsLiteral
){
1980 il
.Emit(OpCodes
.Pop
);
1981 continue; //instance nested class, bail out.
1983 if (field
is JSField
)
1984 il
.Emit(OpCodes
.Ldfld
, (FieldInfo
)((JSField
)field
).GetMetaData());
1985 else if (field
is JSFieldInfo
)
1986 il
.Emit(OpCodes
.Ldfld
, ((JSFieldInfo
)field
).field
);
1988 il
.Emit(OpCodes
.Ldfld
, (FieldInfo
)field
);
1989 Convert
.Emit(this, il
, field
.FieldType
, rtype
);
1990 }else if (member
is PropertyInfo
){
1991 MethodInfo getter
= JSProperty
.GetGetMethod((PropertyInfo
)member
, true);
1992 getter
= this.GetMethodInfoMetadata(getter
);
1993 if (getter
.IsVirtual
&& !getter
.IsFinal
&& (!t
.IsSealed
|| t
.IsValueType
))
1994 il
.Emit(OpCodes
.Callvirt
, getter
);
1996 il
.Emit(OpCodes
.Call
, getter
);
1997 Convert
.Emit(this, il
, getter
.ReturnType
, rtype
);
1999 il
.Emit(OpCodes
.Br
, (Label
)done
);
2001 next
= il
.DefineLabel();
2004 if (!needObject
&& !getObjectFromLateBindingInstance
)
2005 il
.Emit(OpCodes
.Ldloc
, objectLocal
);
2010 private Object
TranslateToSpeculativeEarlyBoundCalls(ILGenerator il
, Type rtype
, ASTList argList
, bool construct
, bool brackets
){
2011 this.giveErrors
= false;
2013 bool needObject
= true;
2014 LocalBuilder objectLocal
= null;
2015 Label next
= il
.DefineLabel();
2016 IReflect
[] classes
= this.GetAllEligibleClasses();
2018 //dealing with "new ob.foo(...)" or "new ob.foo[...]".
2019 //Early binding only makes sense if foo is a nested type marked as protected or package
2020 //But nested types are static and hence will not show up late bound via the object.
2021 //There is the possibility that a programmer can declare a static field and initialize it to a type.
2022 //In that case late bound access works if the field is public, but not otherwise.
2023 //This does not seem like a core scenario that justifies a lot of code inside this if statement.
2026 Debug
.Assert(argList
.count
== 0 || this.argIRs
.Length
== argList
.count
);
2027 foreach (IReflect c
in classes
){
2028 MemberInfo
[] members
= c
.GetMember(this.name
, BindingFlags
.Public
|BindingFlags
.NonPublic
|BindingFlags
.Instance
);
2030 // This code generation does not account for the case ob.foo(...) where ob.foo is a property
2031 // with zero arguments. The code should get the property followed by a call on the
2032 // returned object. For this case, we don't emit the speculative IL and let the late bound
2035 MemberInfo mem
= JSBinder
.SelectCallableMember(members
, this.argIRs
);
2036 if (mem
!= null && mem
.MemberType
== MemberTypes
.Property
)
2038 ParameterInfo
[] parameters
;
2039 meth
= ((PropertyInfo
)mem
).GetGetMethod(true);
2040 if (meth
== null || (parameters
= meth
.GetParameters()) == null || parameters
.Length
== 0)
2044 meth
= mem
as MethodInfo
;
2047 if (!Binding
.CheckParameters(meth
.GetParameters(), this.argIRs
, argList
, this.context
, 0, true, false))
2049 //If meth is a base class method or if meth is an override of a base class method and the base class is in the same package as c
2050 //there is no need to have an instance check for c
2051 if (meth
is JSFieldMethod
){
2052 FunctionObject func
= ((JSFieldMethod
)meth
).func
;
2053 if (func
!= null && (func
.attributes
& MethodAttributes
.NewSlot
) == 0 && ((ClassScope
)c
).ParentIsInSamePackage())
2055 }else if (meth
is JSWrappedMethod
&& ((JSWrappedMethod
)meth
).obj
is ClassScope
&& ((JSWrappedMethod
)meth
).GetPackage() == ((ClassScope
)c
).package
)
2058 if (!this.Accessible(false)) continue;
2061 this.TranslateToILObject(il
, Typeob
.Object
, false);
2062 objectLocal
= il
.DeclareLocal(Typeob
.Object
);
2063 il
.Emit(OpCodes
.Stloc
, objectLocal
);
2064 done
= il
.DefineLabel();
2066 Type t
= meth
.DeclaringType
;
2067 il
.Emit(OpCodes
.Ldloc
, objectLocal
);
2068 il
.Emit(OpCodes
.Isinst
, t
);
2069 LocalBuilder objectTemp
= il
.DeclareLocal(t
);
2070 il
.Emit(OpCodes
.Dup
);
2071 il
.Emit(OpCodes
.Stloc
, objectTemp
);
2072 il
.Emit(OpCodes
.Brfalse
, next
);
2073 il
.Emit(OpCodes
.Ldloc
, objectTemp
);
2074 Binding
.PlaceArgumentsOnStack(il
, meth
.GetParameters(), argList
, 0, 0, Binding
.ReflectionMissingCW
);
2075 meth
= this.GetMethodInfoMetadata(meth
);
2076 if (meth
.IsVirtual
&& !meth
.IsFinal
&& (!t
.IsSealed
|| t
.IsValueType
))
2077 il
.Emit(OpCodes
.Callvirt
, meth
);
2079 il
.Emit(OpCodes
.Call
, meth
);
2080 Convert
.Emit(this, il
, meth
.ReturnType
, rtype
);
2081 il
.Emit(OpCodes
.Br
, (Label
)done
);
2083 next
= il
.DefineLabel();
2085 }catch(AmbiguousMatchException
){}
2089 il
.Emit(OpCodes
.Ldloc
, objectLocal
);
2094 internal static void TranslateToStelem(ILGenerator il
, Type etype
){
2095 switch(Type
.GetTypeCode(etype
)){
2096 case TypeCode
.SByte
:
2097 case TypeCode
.Boolean
:
2099 il
.Emit(OpCodes
.Stelem_I1
); break;
2100 case TypeCode
.Int16
:
2102 case TypeCode
.UInt16
:
2103 il
.Emit(OpCodes
.Stelem_I2
); break;
2104 case TypeCode
.Int32
:
2105 case TypeCode
.UInt32
:
2106 il
.Emit(OpCodes
.Stelem_I4
); break;
2107 case TypeCode
.Int64
:
2108 case TypeCode
.UInt64
:
2109 il
.Emit(OpCodes
.Stelem_I8
); break;
2110 case TypeCode
.Single
:
2111 il
.Emit(OpCodes
.Stelem_R4
); break;
2112 case TypeCode
.Double
:
2113 il
.Emit(OpCodes
.Stelem_R8
); break;
2114 case TypeCode
.Decimal
:
2115 case TypeCode
.DateTime
:
2116 case TypeCode
.String
:
2117 case TypeCode
.Object
:
2118 if (etype
.IsValueType
){
2119 il
.Emit(OpCodes
.Stobj
, etype
);
2121 il
.Emit(OpCodes
.Stelem_Ref
);
2126 private void WarnIfNotFullyResolved(){
2127 if (this.isFullyResolved
|| this.member
== null) return;
2128 if (this.member
is JSVariableField
&& ((JSVariableField
)this.member
).type
== null) return;
2129 if (!this.Engine
.doFast
&& this.member
is IWrappedMember
) return;
2130 ScriptObject scope
= Globals
.ScopeStack
.Peek();
2131 while (scope
!= null){
2132 if (scope
is WithObject
&& !((WithObject
)scope
).isKnownAtCompileTime
){
2133 this.context
.HandleError(JSError
.AmbiguousBindingBecauseOfWith
);
2135 }else if (scope
is ActivationObject
&& !((ActivationObject
)scope
).isKnownAtCompileTime
){
2136 this.context
.HandleError(JSError
.AmbiguousBindingBecauseOfEval
);
2139 scope
= scope
.GetParent();
2143 private void WarnIfObsolete(){
2144 Binding
.WarnIfObsolete(this.member
, this.context
);
2147 internal static void WarnIfObsolete(MemberInfo member
, Context context
){
2150 String message
= null;
2151 bool isError
= false;
2152 Object
[] custAttribs
= CustomAttribute
.GetCustomAttributes(member
, typeof(ObsoleteAttribute
), false);
2153 if (custAttribs
!= null && custAttribs
.Length
> 0){
2154 ObsoleteAttribute attr
= (ObsoleteAttribute
)custAttribs
[0];
2155 message
= attr
.Message
;
2156 isError
= attr
.IsError
;
2158 custAttribs
= CustomAttribute
.GetCustomAttributes(member
, typeof(NotRecommended
), false);
2159 if (custAttribs
!= null && custAttribs
.Length
> 0){
2160 NotRecommended attr
= (NotRecommended
)custAttribs
[0];
2161 message
= ": " + attr
.Message
;
2166 context
.HandleError(JSError
.Deprecated
, message
, isError
);
2170 private MethodInfo
GetMethodInfoMetadata(MethodInfo method
) {
2171 if (method
is JSMethod
)
2172 return ((JSMethod
)method
).GetMethodInfo(this.compilerGlobals
);
2173 if (method
is JSMethodInfo
)
2174 return ((JSMethodInfo
)method
).method
;